import os
from typing import Dict, Any, List, Optional

import numpy as np
import pandas as pd
from models.matching_result import (
    ShipmentAllocation,
    RouteUtilization,
    MatchingSummary,
    MatchingResult,
    ProcessStep,
    MatchingProcess
)

from config import settings


class DataProcessor:
    """
    数据处理类，用于处理CSV文件和匹配结果
    """

    def __init__(self):
        self.shipments_data = None
        self.routes_data = None
        self.network_data = None
        self.cooperation_data = None
        self.matching_results = None
        self.process_data = None

    def health_check(self) -> Dict[str, Any]:
        """
        健康检查，返回各个数据模块的状态
        """
        return {
            "shipments_loaded": self.shipments_data is not None,
            "routes_loaded": self.routes_data is not None,
            "network_loaded": self.network_data is not None,
            "cooperation_loaded": self.cooperation_data is not None,
            "results_loaded": self.matching_results is not None,
            "process_loaded": self.process_data is not None
        }

    def load_shipments_data(self, file_path: str = None) -> Dict[str, Any]:
        """
        加载货物数据
        """
        # 如果没有提供文件路径，使用配置中的默认路径
        if file_path is None:
            file_path = settings.SHIPMENT_DATA_FILE
            
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")

        # 读取CSV文件
        df = pd.read_csv(file_path)
        self.shipments_data = df.to_dict('records')

        return {
            "total_count": len(self.shipments_data),
            "data": self.shipments_data
        }

    def load_routes_data(self, file_path: str = None) -> Dict[str, Any]:
        """
        加载路线数据
        """
        # 如果没有提供文件路径，使用配置中的默认路径
        if file_path is None:
            file_path = settings.ROUTE_DATA_FILE
            
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")

        # 读取CSV文件
        df = pd.read_csv(file_path)
        self.routes_data = df.to_dict('records')

        return {
            "total_count": len(self.routes_data),
            "data": self.routes_data
        }

    def load_network_data(self, file_path: str = None) -> Dict[str, Any]:
        """
        加载网络数据
        """
        # 如果没有提供文件路径，使用配置中的默认路径
        if file_path is None:
            file_path = settings.NETWORK_DATA_FILE
            
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")

        # 读取CSV文件
        df = pd.read_csv(file_path)
        self.network_data = df.to_dict('records')

        return {
            "total_count": len(self.network_data),
            "data": self.network_data
        }

    def load_cooperation_data(self, file_path: str = None) -> Dict[str, Any]:
        """
        加载合作参数数据
        """
        # 如果没有提供文件路径，使用配置中的默认路径
        if file_path is None:
            file_path = settings.COOPERATION_DATA_FILE
            
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")

        # 读取CSV文件
        df = pd.read_csv(file_path)
        self.cooperation_data = df.to_dict('records')

        return {
            "total_count": len(self.cooperation_data),
            "data": self.cooperation_data
        }

    def load_matching_results(self, file_path: str = None) -> Dict[str, Any]:
        """
        加载匹配结果数据
        """
        # 如果没有提供文件路径，使用默认结果文件路径
        if file_path is None:
            file_path = os.path.join(settings.RESULT_DIR, "stable_matching.csv")
            
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"File not found: {file_path}")

        # 读取CSV文件
        df = pd.read_csv(file_path)
        self.matching_results = df.to_dict('records')

        return {
            "total_count": len(self.matching_results),
            "data": self.matching_results
        }
        
    def load_matching_results_data(self, results_data: Dict[str, Any]) -> None:
        """
        直接加载匹配结果数据（来自C++程序）
        """
        self.matching_results = results_data

    def process_matching_results(self, results_data: Optional[Dict[str, Any]] = None) -> MatchingResult:
        """
        处理匹配结果数据
        """
        if results_data is None:
            if self.matching_results is not None:
                results_data = self.matching_results
            else:
                results_data = self._generate_sample_results()

        # 处理从C++程序获取的结果数据
        summary = self._generate_summary(results_data)
        shipments_allocation = self._process_shipments_allocation(results_data)
        routes_utilization = self._process_routes_utilization(results_data)

        # 创建匹配结果对象
        matching_result = MatchingResult(
            summary=MatchingSummary(**summary),
            shipments_allocation=[ShipmentAllocation(**item) for item in shipments_allocation],
            routes_utilization=[RouteUtilization(**item) for item in routes_utilization]
        )

        return matching_result

    def process_matching_process(self, process_data: Optional[List[Dict[str, Any]]] = None) -> MatchingProcess:
        """
        处理匹配过程数据
        """
        if process_data is None:
            if self.process_data is not None:
                process_data = self.process_data
            else:
                process_data = self._generate_sample_process()

        # 存储过程数据
        self.process_data = process_data

        # 处理过程数据
        steps = []
        for step in process_data:
            processed_step = ProcessStep(
                iteration=step.get("iteration", 0),
                action=step.get("action", ""),
                blocking_pairs=step.get("blocking_pairs", 0),
                matched_shipments=step.get("matched_shipments", 0),
                details=step.get("details", {})
            )
            steps.append(processed_step)

        # 创建匹配过程对象
        matching_process = MatchingProcess(steps=steps)

        return matching_process

    def _generate_summary(self, results_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        生成摘要信息
        """
        # 如果是来自C++程序的结果，格式会不同
        if "summary" in results_data:
            cpp_summary = results_data["summary"]
            return {
                "total_shipments": cpp_summary.get("total_shipments", 0),
                "matched_shipments": cpp_summary.get("matched_shipments", 0),
                "unmatched_shipments": max(0, cpp_summary.get("total_shipments", 0) - cpp_summary.get("matched_shipments", 0)),
                "total_capacity": 0,  # 需要从路线数据中计算
                "matched_capacity": 0,  # 需要从路线数据中计算
                "stability": cpp_summary.get("stability", False),
                "execution_time": cpp_summary.get("execution_time", 0),
                "iterations": cpp_summary.get("iterations", 0)
            }
        else:
            return {
                "total_shipments": results_data.get("total_shipments", 0),
                "matched_shipments": results_data.get("matched_shipments", 0),
                "unmatched_shipments": results_data.get("unmatched_shipments", 0),
                "total_capacity": results_data.get("total_capacity", 0),
                "matched_capacity": results_data.get("matched_capacity", 0),
                "stability": results_data.get("stability", False),
                "execution_time": results_data.get("execution_time", 0),
                "iterations": results_data.get("iterations", 0)
            }

    def _process_shipments_allocation(self, results_data: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        处理货物分配数据
        """
        # 如果是来自C++程序的结果
        if "shipments_assignment" in results_data:
            assignments = results_data["shipments_assignment"]
            processed_assignments = []
            for i, assignment in enumerate(assignments):
                # 处理shipment_id，确保它是一个有效的整数
                shipment_id = assignment.get("shipment_id", i+1)
                if isinstance(shipment_id, str) and shipment_id.strip() == '':
                    shipment_id = i + 1  # 使用索引作为默认值
                else:
                    try:
                        shipment_id = int(shipment_id)
                    except (ValueError, TypeError):
                        shipment_id = i + 1  # 使用索引作为默认值
                
                processed_assignments.append({
                    "shipment_id": shipment_id,
                    "origin": f"Node_{i % 10}",
                    "destination": f"Node_{(i + 5) % 10}",
                    "assigned_route": assignment.get("assigned_route", "Self"),
                    "cost": round(np.random.uniform(100, 1000), 2),
                    "preference_rank": i % 4 + 1
                })
            return processed_assignments
        else:
            # 示例处理逻辑
            return [
                {
                    "shipment_id": i,
                    "origin": f"Node_{i % 10}",
                    "destination": f"Node_{(i + 5) % 10}",
                    "assigned_route": f"Route_{i % 5}" if i % 5 != 0 else "Self",
                    "cost": round(np.random.uniform(100, 1000), 2),
                    "preference_rank": i % 4 + 1
                }
                for i in range(1, results_data.get("total_shipments", 100) + 1)
            ]

    def _process_routes_utilization(self, results_data: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        处理路线利用率数据
        """
        # 示例处理逻辑
        return [
            {
                "route_id": f"Route_{i}",
                "capacity": 500,
                "used_capacity": round(np.random.uniform(300, 500)),
                "utilization_rate": round(np.random.uniform(0.6, 1.0), 2),
                "assigned_shipments": int(np.random.uniform(10, 30))
            }
            for i in range(1, 11)
        ]

    def _generate_sample_results(self) -> Dict[str, Any]:
        """
        生成示例结果数据
        """
        return {
            "total_shipments": 100,
            "matched_shipments": 85,
            "unmatched_shipments": 15,
            "total_capacity": 5000,
            "matched_capacity": 4200,
            "stability": True,
            "execution_time": 2.5,
            "iterations": 150
        }

    def _generate_sample_process(self) -> List[Dict[str, Any]]:
        """
        生成示例过程数据
        """
        return [
            {
                "iteration": 1,
                "action": "initial_matching",
                "blocking_pairs": 5,
                "matched_shipments": 70
            },
            {
                "iteration": 2,
                "action": "resolve_blocking_pairs",
                "blocking_pairs": 3,
                "matched_shipments": 75
            },
            {
                "iteration": 3,
                "action": "optimize_matching",
                "blocking_pairs": 1,
                "matched_shipments": 80
            }
        ]

    def cache_data(self, key: str, data: Any) -> None:
        """
        缓存数据
        """
        # 简单的内存缓存实现
        setattr(self, f"cached_{key}", data)

    def get_cached_data(self, key: str) -> Any:
        """
        获取缓存数据
        """
        return getattr(self, f"cached_{key}", None)

    def clear_cache(self) -> None:
        """
        清除所有缓存数据
        """
        cache_attrs = [attr for attr in dir(self) if attr.startswith("cached_")]
        for attr in cache_attrs:
            delattr(self, attr)